package com.api.syh56.shengyunhui.service.impl;

import com.api.syh56.shengyunhui.common.BaseUserInfo;
import com.api.syh56.shengyunhui.common.CommonResult;
import com.api.syh56.shengyunhui.common.Constants;
import com.api.syh56.shengyunhui.common.UserInfoEnu;
import com.api.syh56.shengyunhui.entity.PayInfo;
import com.api.syh56.shengyunhui.entity.Quote;
import com.api.syh56.shengyunhui.entity.User;
import com.api.syh56.shengyunhui.entity.Waybill;
import com.api.syh56.shengyunhui.exception.BaseException;
import com.api.syh56.shengyunhui.properties.WechatProperties;
import com.api.syh56.shengyunhui.service.*;
import com.api.syh56.shengyunhui.util.CodeToOidUtil;
import com.api.syh56.shengyunhui.util.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.app.AppServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import static com.wechat.pay.java.core.http.Constant.*;
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_SERIAL;

@Service
@Slf4j
public class NotifyServiceImpl implements NotifyService {

    @Autowired
    QuoteService quoteService;

    @Autowired
    WayBillService wayBillService;

    @Autowired
    private UserService userService;

    @Autowired
    private PayInfoService payInfoService;

    @Autowired
    private RSAAutoCertificateConfig rsaAutoCertificateConfig;

    @Autowired
    private JsapiServiceExtension jsapiServiceExtension;

    @Autowired
    private AppServiceExtension appServiceExtension;

    @Autowired
    private RefundService refundService;

    @Autowired
    private CodeToOidUtil codeToOidUtil;

    @Autowired
    private WechatProperties wechatProperties;

    @Override
    public Transaction wechatPayTradeParser(HttpServletRequest request, HttpServletResponse response) {
        //获取body
        String body = HttpUtil.readData(request);

        //时间戳
        String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
        //随机串
        String nonce = request.getHeader(WECHAT_PAY_NONCE);
        //微信传递过来的签名
        String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
        //证书序列号（微信平台）
        String serialNumber = request.getHeader(WECHAT_PAY_SERIAL);

        log.info("通知回调请求参数: body: {} ,nonceStr: {} ,signature: {} ,serialNo: {} ,timestamp: {}", body, nonce,
                signature,
                serialNumber,
                timestamp);
        // 签名的验证及解密
        // 构建request，传入必要参数
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serialNumber)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                //若未设置signType，默认值为 WECHATPAY2-SHA256-RSA2048
                //.signType(signType)
                .body(body)
                .build();

//        NotificationRequest  notificationRequest = new NotificationRequest.Builder()
//                .withSerialNumber(serialNumber)
//                .withNonce(nonce)
//                .withSignature(signature)
//                .withTimestamp(timestamp)
//                .withBody(body)
//                .build();
        // 初始化 NotificationParser验签解析
        NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
        // 验签并解密报文
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        log.info("支付通知的解密数据: {}", transaction);
        return transaction;
    }

    public RefundNotification wechatPayRefundPaser(HttpServletRequest request, HttpServletResponse response){
        //获取body
        String body = HttpUtil.readData(request);

        //时间戳
        String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
        //随机串
        String nonce = request.getHeader(WECHAT_PAY_NONCE);
        //微信传递过来的签名
        String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
        //证书序列号（微信平台）
        String serialNumber = request.getHeader(WECHAT_PAY_SERIAL);

        log.info("通知回调请求参数: body: {} ,nonceStr: {} ,signature: {} ,serialNo: {} ,timestamp: {}",
                body, nonce,
                signature,
                serialNumber,
                timestamp);
        // 签名的验证及解密
        // 构建request，传入必要参数
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serialNumber)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                //若未设置signType，默认值为 WECHATPAY2-SHA256-RSA2048
                //.signType(signType)
                .body(body)
                .build();

        // 初始化 NotificationParser验签解析
        NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
        // 验签并解密报文
        RefundNotification refundNotification = parser.parse(requestParam, RefundNotification.class);
        return refundNotification;
    }








    public Map<String,String> jsapiPrepayWithRequestPaymentResponse(Map<String,String> requestBody) throws Exception {

        // 直接从 requestBody 中获取参数
        String code = requestBody.get("code");
        Long waybillId = Long.parseLong(requestBody.get("id"));
        Long quoteId = Long.parseLong(requestBody.get("qid"));
        //金额类型  deposit\amount_total
        String priceType = requestBody.get("type");
        //mini OR app
        String platform = requestBody.get("platform");

        Long uid = Long.valueOf(BaseUserInfo.get(UserInfoEnu.id.getCode()));
        User user = userService.getById(uid);

        Waybill waybill = wayBillService.getById(waybillId);

        Quote quote = quoteService.getById(quoteId);
        Long driverId = quote.getDriverId();


        //判断是否为运单货主本人
        if(!uid.equals(waybill.getShiperId())){
            throw new BaseException("非运单货主本人操作");
        }

        //支付金额(以分为单位)（定金 金额）
        int price = 999;
        BigDecimal tmp_price = BigDecimal.valueOf(0);
        String payDescription = "";//描述
        Short amountType = 0;//金额类型
        String orderNum = "";

        if ("deposit".equals(priceType)){
            tmp_price = quote.getDeposit();
            price =  tmp_price.multiply(new BigDecimal("100")).intValue();
            payDescription = waybill.getWaybillNumber()+" 定金";
            amountType = Constants.AmountType.DEPOSIT;
            orderNum = waybill.getWaybillNumber()+"D";
        }else {
            tmp_price = quote.getOfferPrice();
            price = tmp_price.intValue()*100;
            payDescription = waybill.getWaybillNumber()+" 运费";
            amountType = Constants.AmountType.SHIPFEE;
            orderNum = waybill.getWaybillNumber()+"Y";
        }

        PrepayRequest jsapirequest = new PrepayRequest();

        Payer payer = new Payer();
        Map<String, String> stringStringMap = codeToOidUtil.getOpenIdByCode(code);
        String openid = stringStringMap.get("openid");
        System.out.println(openid);
        //微信用户openid
        payer.setOpenid(openid);

        Amount amount = new Amount();
        amount.setTotal(price);
        amount.setCurrency("CNY");
        jsapirequest.setAmount(amount);
        jsapirequest.setAppid(wechatProperties.getAppid());
        jsapirequest.setMchid(wechatProperties.getMerchantId());
        //支付描述
        jsapirequest.setDescription(payDescription);
        //支付通知消息回调
        jsapirequest.setNotifyUrl(wechatProperties.getNotifyUrl());//回调地址
        //是否支持开发票
        jsapirequest.setSupportFapiao(true);
        //支付超时时间设为30分钟
        ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai")).plusMinutes(30);
        // 格式化为RFC 3339格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
        String formattedDateTime = zonedDateTime.format(formatter);
        jsapirequest.setTimeExpire(formattedDateTime);


        //商户系统支付订单号(运单编号)
        log.info("订单号:{}", orderNum);
        jsapirequest.setOutTradeNo(orderNum);
        //付款人
        jsapirequest.setPayer(payer);
        //附加信息（运单id 金额类型）
        Map<String, Object> additionalInfo = new HashMap<>();
        additionalInfo.put("waybillId", waybillId.toString());
        additionalInfo.put("priceType", priceType);
        additionalInfo.put("driverId", quote.getDriverId().toString());
        additionalInfo.put("quoteOfferPrice",quote.getOfferPrice());
        System.out.println(additionalInfo);


        // 将Map转换为JSON字符串
        String json = new Gson().toJson(additionalInfo);
        jsapirequest.setAttach(json);
        // response包含了调起支付所需的所有参数，可直接用于前端调起支付
        PrepayWithRequestPaymentResponse prepayWithRequestPaymentResponse = jsapiServiceExtension.prepayWithRequestPayment(jsapirequest);
        System.out.println(prepayWithRequestPaymentResponse);

        PayInfo payInfo = new PayInfo().builder()
                .waybillId(waybillId)
                .PayNum(orderNum)
                .payer(uid)
                .payee(driverId)
                .amount(tmp_price)
                .amountType(amountType)
                .state(Constants.PaymentStatus.UN_PAID)
                .build();
        payInfoService.save(payInfo);


        Map<String, String> data = new HashMap<>();
        data.put("appid",prepayWithRequestPaymentResponse.getAppId());//appid
        data.put("timeStamp",prepayWithRequestPaymentResponse.getTimeStamp());
        data.put("nonceStr",prepayWithRequestPaymentResponse.getNonceStr());
        data.put("package",prepayWithRequestPaymentResponse.getPackageVal());
        data.put("signType",prepayWithRequestPaymentResponse.getSignType());//签名方式
        data.put("paySign",prepayWithRequestPaymentResponse.getPaySign());
        System.out.println(data);
        return data;
    }

    public Map<String,String> AppPrepayWithRequestPaymentResponse(Map<String,String> requestBody) throws Exception{
        // 直接从 requestBody 中获取参数
        String code = requestBody.get("code");
        Long waybillId = Long.parseLong(requestBody.get("id"));
        Long quoteId = Long.parseLong(requestBody.get("qid"));
        //金额类型  deposit\amount_total
        String priceType = requestBody.get("type");
        //mini OR app
        String platform = requestBody.get("platform");

        Long uid = Long.valueOf(BaseUserInfo.get(UserInfoEnu.id.getCode()));
        User user = userService.getById(uid);

        Waybill waybill = wayBillService.getById(waybillId);

        Quote quote = quoteService.getById(quoteId);
        Long driverId = quote.getDriverId();


        //判断是否为运单货主本人
        if(!uid.equals(waybill.getShiperId())){
            throw new BaseException("非运单货主本人操作");
        }

        //支付金额(以分为单位)（定金 金额）
        int price = 999;
        BigDecimal tmp_price = BigDecimal.valueOf(0);
        String payDescription = "";//描述
        Short amountType = 0;//金额类型
        String orderNum = "";

        if ("deposit".equals(priceType)){
            tmp_price = quote.getDeposit();
            price =  tmp_price.multiply(new BigDecimal("100")).intValue();
            payDescription = waybill.getWaybillNumber()+" 定金";
            amountType = Constants.AmountType.DEPOSIT;
            orderNum = waybill.getWaybillNumber()+"D";
        }else {
            tmp_price = quote.getOfferPrice();
            price = tmp_price.intValue()*100;
            payDescription = waybill.getWaybillNumber()+" 运费";
            amountType = Constants.AmountType.SHIPFEE;
            orderNum = waybill.getWaybillNumber()+"Y";
        }

        // request.setXxx(val)设置所需参数，具体参数可见Request定义
        com.wechat.pay.java.service.payments.app.model.PrepayRequest AppprepayRequest = new com.wechat.pay.java.service.payments.app.model.PrepayRequest();

        /**
         * App无需Payer付款人
         */
//        Payer payer = new Payer();
//        Map<String, String> stringStringMap = codeToOidUtil.getOpenIdByCode(code);
//        String openid = stringStringMap.get("openid");
//        System.out.println(openid);
//        //微信用户openid
//        payer.setOpenid(openid);

        com.wechat.pay.java.service.payments.app.model.Amount amount = new com.wechat.pay.java.service.payments.app.model.Amount();
        amount.setTotal(price);
        amount.setCurrency("CNY");
        AppprepayRequest.setAmount(amount);
        AppprepayRequest.setAppid(wechatProperties.getAppid());
        AppprepayRequest.setMchid(wechatProperties.getMerchantId());
        //支付描述
        AppprepayRequest.setDescription(payDescription);
        //支付通知消息回调
        AppprepayRequest.setNotifyUrl(wechatProperties.getNotifyUrl());//回调地址
        //是否支持开发票
        AppprepayRequest.setSupportFapiao(true);
        //支付超时时间设为30分钟
        ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai")).plusMinutes(30);
        // 格式化为RFC 3339格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
        String formattedDateTime = zonedDateTime.format(formatter);
        AppprepayRequest.setTimeExpire(formattedDateTime);


        //商户系统支付订单号(运单编号)
        log.info("订单号:{}", orderNum);
        AppprepayRequest.setOutTradeNo(orderNum);
        //付款人
//        AppprepayRequest.setPayer(payer);
        //附加信息（运单id 金额类型）
        Map<String, Object> additionalInfo = new HashMap<>();
        additionalInfo.put("waybillId", waybillId.toString());
        additionalInfo.put("priceType", priceType);
        additionalInfo.put("driverId", quote.getDriverId().toString());
        additionalInfo.put("quoteOfferPrice",quote.getOfferPrice());
        System.out.println(additionalInfo);


        // 将Map转换为JSON字符串
        String json = new Gson().toJson(additionalInfo);
        AppprepayRequest.setAttach(json);
        com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse prepayWithRequestPaymentResponse = appServiceExtension.prepayWithRequestPayment(AppprepayRequest);

        System.out.println(prepayWithRequestPaymentResponse);

        PayInfo payInfo = new PayInfo().builder()
                .waybillId(waybillId)
                .PayNum(orderNum)
                .payer(uid)
                .payee(driverId)
                .amount(tmp_price)
                .amountType(amountType)
                .state(Constants.PaymentStatus.UN_PAID)
                .build();
        payInfoService.save(payInfo);


        Map<String, String> data = new HashMap<>();
        data.put("appid",prepayWithRequestPaymentResponse.getAppid());//appid
        data.put("timeStamp",prepayWithRequestPaymentResponse.getTimestamp());
        data.put("nonceStr",prepayWithRequestPaymentResponse.getNonceStr());
        data.put("package",prepayWithRequestPaymentResponse.getPackageVal());
        data.put("partnerid",prepayWithRequestPaymentResponse.getPartnerId());//商户号mchid对应的值
        data.put("Sign",prepayWithRequestPaymentResponse.getSign());//签名
        System.out.println(data);
        return data;
    }

}
